package com.anlogic.sdk.bootimage.model;

import com.anlogic.sdk.bootimage.model.options.AuthenticationType;
import com.anlogic.sdk.bootimage.model.options.EncryptionType;
import com.anlogic.sdk.bootimage.model.options.FsblDestCpuType;
import com.anlogic.sdk.bootimage.model.options.PartionType;
import com.anlogic.sdk.bootimage.model.options.MpSoCKeyStore;
import com.anlogic.sdk.utils.FileUtils;
import com.anlogic.sdk.utils.StringUtils;
import com.anlogic.sdk.utils.options.ChipType;
import com.google.gson.Gson;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;

public class BootGenModel {
	public enum KeyStore {
		BBRAM, EFUSE;
	}

	private String bifFile = "";

	private String importBifFile = "";

	private boolean isNew = true;

	private boolean useAuthentication;

	private String ppkFile;

	private String pskFile;

	private String spkFile;

	private String sskFile;

	private String spkSignFile;

	private AuthenticationType authType = AuthenticationType.NONE;

	private boolean isBHAuth;
	
	private boolean isQspiX1;
	
	private boolean isMmcClk;
	
	private boolean genAuthKeys;
	
	private boolean genSpkSig;

	private String spkId;
	
	private String fillBytes;

	private FsblDestCpuType fsblDestCpuType = FsblDestCpuType.A35_0;

	private boolean useEncryption;

	private String keyFile;

	private KeyStore keyStore;

	private boolean optionalKey;

	private EncryptionType encryptionType = EncryptionType.NONE;
	
	private MpSoCKeyStore mpSoCKeyStore = MpSoCKeyStore.EFUSE_RED;

	private String partName;

	private ChipType chipType = ChipType.DR1M90;

	private List<Partition> partitions;
	
	private String outputFile = "";

	private boolean overwrite;

	private boolean split;

	private boolean editBif;

	private String formatType = "BIN";

	public ChipType getChipType() {
		return this.chipType;
	}

	public void setChipType(ChipType chipType) {
		this.chipType = chipType;
	}

	public String getFormatType() {
		return this.formatType;
	}

	public void setFormatType(String formatType) {
		this.formatType = formatType;
	}

	public BootGenModel() {
		this.partitions = new ArrayList<>();
		clear();
	}

	public String getBifFile() {
		return this.bifFile;
	}

	public void setBifFile(String bifFile) {
		this.bifFile = bifFile;
	}

	public void setImportBifFile(String importBifFile) {
		this.importBifFile = importBifFile;
	}

	public String getImportBifFile() {
		return this.importBifFile;
	}

	public void setSplit(boolean split) {
		this.split = split;
	}

	public boolean isSplit() {
		return this.split;
	}

	public boolean isUseAuthentication() {
		return this.useAuthentication;
	}

	public void setUseAuthentication(boolean useAuthentication) {
		this.useAuthentication = useAuthentication;
	}

	public String getPpkFile() {
		return this.ppkFile;
	}

	public void setPpkFile(String ppkFile) {
		this.ppkFile = ppkFile;
	}

	public String getPskFile() {
		return this.pskFile;
	}

	public void setPskFile(String pskFile) {
		this.pskFile = pskFile;
	}

	public String getSpkFile() {
		return this.spkFile;
	}

	public void setSpkFile(String spkFile) {
		this.spkFile = spkFile;
	}

	public String getSskFile() {
		return this.sskFile;
	}

	public void setSskFile(String sskFile) {
		this.sskFile = sskFile;
	}

	public String getSpkSignFile() {
		return this.spkSignFile;
	}

	public void setSpkSignFile(String spkSignFile) {
		this.spkSignFile = spkSignFile;
	}

	public AuthenticationType getAuthType() {
		return this.authType;
	}

	public void setAuthType(AuthenticationType authType) {
		this.authType = authType;
	}
	
	public AuthenticationType[] getSelectAuthTypeList() {
		if (getAuthType().equals(AuthenticationType.NONE)) {
			return AuthenticationType.values();
		} else {
			AuthenticationType[] array = {AuthenticationType.NONE, getAuthType()};
			return array;
		}
	}
	
	public EncryptionType[] getSelectEncryptTypeList() {
		if (getEncryptionType().equals(EncryptionType.NONE)) {
			return EncryptionType.values();
		} else {
			EncryptionType[] array = {EncryptionType.NONE, getEncryptionType()};
			return array;
		}
	}
	
	public boolean isGenAuthKeys() {
		return this.genAuthKeys;
	}

	public void setGenAuthKeys(boolean genAuthKeys) {
		this.genAuthKeys = genAuthKeys;
	}
	
	public boolean isGenSpkSig() {
		return this.genSpkSig;
	}

	public void setGenSpkSig(boolean genSpkSig) {
		this.genSpkSig = genSpkSig;
	}
	
	public boolean isBHAuth() {
		return this.isBHAuth;
	}

	public void setBHAuth(boolean isBHAuth) {
		this.isBHAuth = isBHAuth;
	}

	public String getSpkId() {
		return this.spkId;
	}

	public void setSpkId(String spkId) {
		this.spkId = spkId;
	}
	
	public String getFillBytes() {
		return this.fillBytes;
	}

	public void setFillBytes(String fillBytes) {
		this.fillBytes = fillBytes;
	}
	
	public boolean isQspiX1() {
		return this.isQspiX1;
	}

	public void setQspiX1(boolean isQspiX1) {
		this.isQspiX1 = isQspiX1;
	}
	
	public boolean isMmcClk() {
		return this.isMmcClk;
	}

	public void setMmcClk(boolean isMmcClk) {
		this.isMmcClk = isMmcClk;
	}
	
	public boolean isUseEncryption() {
		return this.useEncryption;
	}

	public void setUseEncryption(boolean useEncryption) {
		this.useEncryption = useEncryption;
	}

	public String getKeyFile() {
		return this.keyFile;
	}

	public void setKeyFile(String keyFile) {
		this.keyFile = keyFile;
	}

	public KeyStore getKeyStore() {
		return this.keyStore;
	}

	public void setKeyStore(KeyStore keyStore) {
		this.keyStore = keyStore;
	}

	public MpSoCKeyStore getMpSoCKeyStore() {
		return this.mpSoCKeyStore;
	}

	public void setMpSoCKeyStore(MpSoCKeyStore mpSoCKeyStore) {
		this.mpSoCKeyStore = mpSoCKeyStore;
	}

	public EncryptionType getEncryptionType() {
		return this.encryptionType;
	}
	
	public void setEncryptionType(EncryptionType encryptionType) {
		this.encryptionType = encryptionType;
	}
	
	public String getPartName() {
		return this.partName;
	}

	public void setPartName(String partName) {
		this.partName = partName;
	}

	public boolean isOptionalKey() {
		return this.optionalKey;
	}

	public void setOptionalKey(boolean optionalKey) {
		this.optionalKey = optionalKey;
	}

	public FsblDestCpuType getFsblDestCpuType() {
		return this.fsblDestCpuType;
	}

	public void setFsblDestCpuType(FsblDestCpuType fsblDestCpuType) {
		this.fsblDestCpuType = fsblDestCpuType;
	}

	public List<Partition> getPartitions() {
		return this.partitions;
	}
	
	public String getOutputDir() {
		return new File(this.outputFile).getParentFile().getAbsolutePath();
	}

	public String getOutputFile() {
		return this.outputFile;
	}

	public void setOutputFile(String outputFile) {
		this.outputFile = outputFile;
	}

	public boolean isOverwrite() {
		return this.overwrite;
	}

	public void setOverwrite(boolean overwrite) {
		this.overwrite = overwrite;
	}

	public void setEditBif(boolean editBif) {
		this.editBif = editBif;
	}

	public boolean isEditBif() {
		return this.editBif;
	}

	public boolean isOverwriteBif() {
		return ((new File(getBifFile())).exists() && (isEditBif() || isNew()));
	}

	public void addPartition(Partition partition) {
		if (partition.getPartitionType() == PartionType.BOOTLOADER) {
			this.partitions.add(0, partition);
		} else {
			this.partitions.add(partition);
		}
	}

	public boolean isNew() {
		return this.isNew;
	}

	public void setNew(boolean isNew) {
		this.isNew = isNew;
	}

	public boolean hasFsblPartition() {
		for (Partition partition : this.partitions) {
			if (partition.isFsbl())
				return true;
		}
		return false;
	}

	public File getResolvedFile(String fileLoc) {
		IPath iPath;
		if (StringUtils.isEmpty(fileLoc))
			return null;
		Path path = new Path(fileLoc);
		if (!path.isAbsolute()) {
			iPath = (new Path(getBifFile())).removeLastSegments(1).append((IPath) path);
		} else {
			iPath = (IPath) path;
		}
		return iPath.toFile();
	}
	
	public String getCommand() {
		return BifWriter.createBifCommand(this);
	}

	public String getBifContent() {
		return BifWriter.converToString(this);
	}

	public void clear() {
		this.isNew = true;
		this.useAuthentication = false;
		this.ppkFile = "";
		this.pskFile = "";
		this.spkFile = "";
		this.sskFile = "";
		this.spkSignFile = "";
		this.spkId = "";
		this.useEncryption = false;
		this.keyFile = "";
		this.keyStore = KeyStore.BBRAM;
		this.partName = "";
		this.partitions.clear();
		this.overwrite = false;
		this.editBif = false;
		this.split = false;
	}

	public void resetForArchitecture() {
		for (Partition partition : this.partitions) {
			partition.setChipType(getChipType());
			partition.resetForArchitecture();
		}
	}
	
	public boolean checkFileExists(String path) {
		if (path.isEmpty())
			return false;
		File file = getResolvedFile(path);
		return file.exists();
	}
	
	public boolean authKeyLegalityMode0() {
		if (ppkFile.isEmpty() || sskFile.isEmpty() || spkSignFile.isEmpty())
			return false;
		
		if (isGenAuthKeys()) {
			if (!FileUtils.checkFilePathLegality(ppkFile) || !FileUtils.checkFilePathLegality(sskFile)) {
				return false;
			}
		} else {
			if ((!checkFileExists(ppkFile) || !checkFileExists(sskFile))) {
				return false;
			}
		}
		if (isGenSpkSig()) {
			if (!FileUtils.checkFilePathLegality(spkSignFile)) {
				return false;
			}
			if (isGenAuthKeys()) {
				if (!FileUtils.checkFilePathLegality(pskFile)) {
					return false;
				}
			} else {
				if (!checkFileExists(pskFile)) {
					return false;
				}
			}
		} else {
			if (!checkFileExists(spkSignFile)) {
				return false;
			}
		}
		return true;
	}
	
	public boolean authKeyLegalityMode1() {
		if (pskFile.isEmpty() || sskFile.isEmpty())
			return false;
		
		if (isGenAuthKeys()) {
			if (!FileUtils.checkFilePathLegality(pskFile) || !FileUtils.checkFilePathLegality(sskFile)) {
				return false;
			}
		} else if (!checkFileExists(pskFile) || !checkFileExists(sskFile)) {
			return false;
		}
			
		return true;
	}
	
	public boolean checkAuthKeyLegality() {
		if (authKeyLegalityMode0() || authKeyLegalityMode1()) {
			return true;
		}
		return false;
	}
	
	public boolean checkKeyFileLegality() {
		return FileUtils.checkFilePathLegality(keyFile);
	}
	
	public boolean checkFilePathLegality(String filePath) {
		if (filePath.isEmpty()) {
			return false;
		}
		return FileUtils.checkFilePathLegality(filePath);
	}
	
	public boolean checkKeyFileExist() {
		return checkFileExists(keyFile);
	}
	
	public String toJsonString() {
		Gson gson = new Gson();
		return gson.toJson(this);
	}

	public static BootGenModel readJsonString(String json) {
		Gson gson = new Gson();
		return (BootGenModel) gson.fromJson(json, BootGenModel.class);
	}
}
